/*
 * Copyright (c) 2019-2020, https://api.iot.10086.cn/(https://gitee.com/cmcc-iot-api/iot-card-open-application/).
 */
package cn.iot.card.open.sim.service;

import cn.iot.card.open.constants.Constants;
import cn.iot.card.open.constants.ErrorCode;
import cn.iot.card.open.constants.UrlConstants;
import cn.iot.card.open.ec.dto.ResponseDto;
import cn.iot.card.open.modular.model.ResultDTO;
import cn.iot.card.open.modular.token.TokenService;
import cn.iot.card.open.pojo.page.LayuiPageFactory;
import cn.iot.card.open.pojo.page.LayuiPageInfo;
import cn.iot.card.open.sim.dto.siminfo.*;
import cn.iot.card.open.sim.warpper.SimInfoForGprsWrapper;
import cn.iot.card.open.util.ApiRequestUtil;
import cn.iot.card.open.util.CommonUtil;
import cn.iot.card.open.util.JsonUtil;
import cn.stylefeng.roses.core.reqres.response.ResponseData;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 物联卡综合信息---GPRS
 *
 * @author zhanlele
 * @date 20200312 11:52:08
 * @modify 20200312 zhanlele v1.1.2 创建
 * @since v1.1.2
 */
@Service
@Slf4j
public class SimInfoForGprsService {

    @Autowired
    private TokenService tokenService;

    @Autowired
    private ApiRequestUtil apiRequestUtil;

    /**
     * 分割符
     */
    private static final String SEPARATE = "--";

    /**
     * GPRS上网功能重置
     *
     * @param accountId 账户ID
     * @param transId   流水号
     * @param cardType  卡类型
     * @param cardNum   卡号
     * @return 返回 response data
     * @throws Exception
     * @author zhanlele
     * @date 20200312 12:03:42
     * @modify 20200312 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    public ResponseData resetGprsNetFunction(String accountId, String transId, String cardType,
                                             String cardNum) throws Exception {
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO resultDTO = doRequestResetGprsNetFunction(true, accountId, transId, cardType, cardNum);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
            throw new ServiceException(Integer.valueOf(errorCode.getCode()), errorCode.getMsg());
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = resultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token [accountId:{}] of resetGprsNetFunction is invalid and start to get a new token.", transId, accountId);
            resultDTO = doRequestResetGprsNetFunction(false, accountId, transId, cardType, cardNum);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
                throw new ServiceException(Integer.valueOf(errorCode.getCode()), errorCode.getMsg());
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = resultDTO.getMsg();
        }

        log.info("[{}] resetGprsNetFunction result string is {}.", transId, responseStr);
        ResponseDto responseDto = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto>(){});
        code = responseDto.getStatus();
        if (ErrorCode.SUCCESS.getCode().equals(code)) {
            return ResponseData.success();
        } else {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] resetGprsNetFunction error, error message is {}.", transId, responseDto.getMessage());
            ResponseData responseData = new ResponseData();
            responseData.setCode(Integer.valueOf(code));
            responseData.setMessage(responseDto.getMessage());
            return responseData;
        }
    }

    /**
     * 调API，GPRS上网功能重置
     *
     * @param tokenValid token是否有效
     * @param accountId  账户ID
     * @param transId
     * @param cardType   卡类型
     * @param cardNum    卡号
     * @return 返回 result dto
     * @throws Exception
     * @author zhanlele
     * @date 20200312 11:47:28
     * @modify 20200312 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    private ResultDTO doRequestResetGprsNetFunction(boolean tokenValid, String accountId, String transId,
                                                    String cardType, String cardNum) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        parameterMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        switch (cardType) {
            case Constants.REQUEST_PARAM_MSISDN:
                parameterMap.put(Constants.REQUEST_PARAM_MSISDN, cardNum);
                break;
            case Constants.REQUEST_PARAM_ICCID:
                parameterMap.put(Constants.REQUEST_PARAM_ICCID, cardNum);
                break;
            case Constants.REQUEST_PARAM_IMSI:
                parameterMap.put(Constants.REQUEST_PARAM_IMSI, cardNum);
                break;
        }

        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, UrlConstants.OPERATE_RESET_NET_FUNCTION);
        log.info("[{}] resetGprsNetFunction request url is {}.", transId, methodUrl);

        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }

    /**
     * GPRS（自主）限速
     *
     * @param accountId         账户ID
     * @param transId           流水号
     * @param gprsLimitSpeedDTO
     * @return 返回 response data
     * @throws Exception
     * @author zhanlele
     * @date 20200312 15:53:19
     * @modify 20200312 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    public ResponseData gprsLimitSpeed(String accountId, String transId, GprsLimitSpeedDTO gprsLimitSpeedDTO) throws Exception {
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO resultDTO = doRequestGprsLimitSpeed(true, accountId, transId, gprsLimitSpeedDTO);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
            throw new ServiceException(Integer.valueOf(errorCode.getCode()), errorCode.getMsg());
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = resultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token [accountId:{}] is invalid and start to get a new token.", transId, accountId);
            resultDTO = doRequestGprsLimitSpeed(false, accountId, transId, gprsLimitSpeedDTO);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
                throw new ServiceException(Integer.valueOf(errorCode.getCode()), errorCode.getMsg());
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = resultDTO.getMsg();
        }

        log.info("[{}] gprsLimitSpeed result string is {}.", transId, responseStr);
        ResponseDto responseDto = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto>(){});
        code = responseDto.getStatus();
        if (ErrorCode.SUCCESS.getCode().equals(code)) {
            return ResponseData.success();
        } else {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] gprsLimitSpeed error, error message is {}.", transId, responseDto.getMessage());
            ResponseData responseData = new ResponseData();
            responseData.setCode(Integer.valueOf(code));
            responseData.setMessage(responseDto.getMessage());
            return responseData;
        }
    }

    /**
     * 调API，GPRS（自主）限速
     *
     * @param tokenValid        token是否有效
     * @param accountId         账户ID
     * @param transId           流水号
     * @param gprsLimitSpeedDTO
     * @return 返回 result dto
     * @throws Exception
     * @author zhanlele
     * @date 20200312 15:50:56
     * @modify 20200312 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    private ResultDTO doRequestGprsLimitSpeed(boolean tokenValid, String accountId, String transId,
                                              GprsLimitSpeedDTO gprsLimitSpeedDTO) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        String cardType = gprsLimitSpeedDTO.getCardType();
        String cardNum = gprsLimitSpeedDTO.getCardNum();
        String apnName = gprsLimitSpeedDTO.getApnName();
        String serviceUsageState = gprsLimitSpeedDTO.getServiceUsageState();
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        parameterMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        switch (cardType) {
            case Constants.REQUEST_PARAM_MSISDN:
                parameterMap.put(Constants.REQUEST_PARAM_MSISDN, cardNum);
                break;
            case Constants.REQUEST_PARAM_ICCID:
                parameterMap.put(Constants.REQUEST_PARAM_ICCID, cardNum);
                break;
            case Constants.REQUEST_PARAM_IMSI:
                parameterMap.put(Constants.REQUEST_PARAM_IMSI, cardNum);
                break;
        }
        parameterMap.put(Constants.REQUEST_PARAM_APNNAME, apnName);
        parameterMap.put(Constants.SERVICE_USAGE_STATE, serviceUsageState);

        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, UrlConstants.OPERATE_GPRS_LIMIT_SPEED);
        log.info("[{}] gprsLimitSpeed request url is {}.", transId, methodUrl);

        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }

    /**
     * GPRS（PCC策略）限速
     *
     * @param accountId            账户ID
     * @param transId              流水号
     * @param gprsPccLimitSpeedDTO
     * @return 返回 response data
     * @throws Exception
     * @author zhanlele
     * @date 20200312 17:48:13
     * @modify 20200312 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    public ResponseData gprsPccLimitSpeed(String accountId, String transId, GprsPccLimitSpeedDTO gprsPccLimitSpeedDTO) throws Exception {
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO resultDTO = doRequestGprsPccLimitSpeed(true, accountId, transId, gprsPccLimitSpeedDTO);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
            throw new ServiceException(Integer.valueOf(errorCode.getCode()), errorCode.getMsg());
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = resultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token [accountId:{}] of gprsPccLimitSpeed is invalid and start to get a new token.", transId, accountId);
            resultDTO = doRequestGprsPccLimitSpeed(false, accountId, transId, gprsPccLimitSpeedDTO);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
                throw new ServiceException(Integer.valueOf(errorCode.getCode()), errorCode.getMsg());
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = resultDTO.getMsg();
        }

        log.info("[{}] gprsPccLimitSpeed result string is {}.", transId, responseStr);
        ResponseDto responseDto = JsonUtil.parseJson(responseStr, new TypeReference<ResponseDto>(){});
        code = responseDto.getStatus();
        if (ErrorCode.SUCCESS.getCode().equals(code)) {
            return ResponseData.success();
        } else {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] gprsPccLimitSpeed error, error message is {}.", transId, responseDto.getMessage());
            ResponseData responseData = new ResponseData();
            responseData.setCode(Integer.valueOf(code));
            responseData.setMessage(responseDto.getMessage());
            return responseData;
        }
    }

    /**
     * 调用API，GPRS（PCC策略）限速
     *
     * @param tokenValid           token是否有效
     * @param accountId            账户ID
     * @param transId              流水号
     * @param gprsPccLimitSpeedDTO
     * @return 返回 result dto
     * @throws Exception
     * @author zhanlele
     * @date 20200312 17:39:48
     * @modify 20200312 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    private ResultDTO doRequestGprsPccLimitSpeed(boolean tokenValid, String accountId, String transId,
                                                 GprsPccLimitSpeedDTO gprsPccLimitSpeedDTO) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        String cardType = gprsPccLimitSpeedDTO.getCardType();
        String cardNum = gprsPccLimitSpeedDTO.getCardNum();
        String apnName = gprsPccLimitSpeedDTO.getApnName();
        String pccCode = gprsPccLimitSpeedDTO.getPccCode();
        String serviceUsageState = gprsPccLimitSpeedDTO.getServiceUsageState();
        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        parameterMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        switch (cardType) {
            case Constants.REQUEST_PARAM_MSISDN:
                parameterMap.put(Constants.REQUEST_PARAM_MSISDN, cardNum);
                break;
            case Constants.REQUEST_PARAM_ICCID:
                parameterMap.put(Constants.REQUEST_PARAM_ICCID, cardNum);
                break;
            case Constants.REQUEST_PARAM_IMSI:
                parameterMap.put(Constants.REQUEST_PARAM_IMSI, cardNum);
                break;
        }
        parameterMap.put(Constants.REQUEST_PARAM_APNNAME, apnName);
        if (StringUtils.isNotBlank(pccCode)) {
            parameterMap.put(Constants.PCC_CODE, pccCode);
        }
        parameterMap.put(Constants.SERVICE_USAGE_STATE, serviceUsageState);

        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, UrlConstants.OPERATE_GPRS_PCC_LIMIT_SPEED);
        log.info("[{}] gprsPccLimitSpeed request url is {}.", transId, methodUrl);

        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }

    /**
     * 流量叠加包订购
     *
     * @param accountId           账户ID
     * @param transId             流水号
     * @param gprsPackageOrderDTO
     * @return 返回 response data
     * @throws Exception
     * @author zhanlele
     * @date 20200312 20:30:21
     * @modify 20200312 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    public ResponseData gprsPackageOrder(String accountId, String transId,
                                         GprsPackageOrderDTO gprsPackageOrderDTO) throws Exception {
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO resultDTO = doRequestGprsPackageOrder(true, accountId, transId, gprsPackageOrderDTO);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
            throw new ServiceException(Integer.valueOf(errorCode.getCode()), errorCode.getMsg());
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = resultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token [accountId:{}] of gprsPackageOrder is invalid and start to get a new token.", transId, accountId);
            resultDTO = doRequestGprsPackageOrder(false, accountId, transId, gprsPackageOrderDTO);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
                throw new ServiceException(Integer.valueOf(errorCode.getCode()), errorCode.getMsg());
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = resultDTO.getMsg();
        }

        log.info("[{}] gprsPackageOrder result string is {}.", transId, responseStr);
        ResponseDto<Map<String, String>> responseDto = JsonUtil.parseJson(responseStr,
                new TypeReference<ResponseDto<Map<String, String>>>(){});
        code = responseDto.getStatus();
        if (ErrorCode.SUCCESS.getCode().equals(code)) {
            return ResponseData.success(JsonUtil.toJson(responseDto.getResult()));
        } else {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] gprsPackageOrder error, error message is {}.", transId, responseDto.getMessage());
            ResponseData responseData = new ResponseData();
            responseData.setCode(Integer.valueOf(code));
            responseData.setMessage(responseDto.getMessage());
            return responseData;
        }
    }

    /**
     * 调用API，流量叠加包订购
     *
     * @param tokenValid          token是否有效
     * @param accountId           账户ID
     * @param transId             流水号
     * @param gprsPackageOrderDTO
     * @return 返回 result dto
     * @throws Exception
     * @author zhanlele
     * @date 20200312 20:25:08
     * @modify 20200312 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    private ResultDTO doRequestGprsPackageOrder(boolean tokenValid, String accountId, String transId,
                                               GprsPackageOrderDTO gprsPackageOrderDTO) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        Map<String, String> parameterMap = new HashMap<>();
        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        parameterMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        parameterMap.put(Constants.REQUEST_PARAM_MSISDN, gprsPackageOrderDTO.getMsisdn());
        parameterMap.put(Constants.ORDER_GPRS_PACKAGE, gprsPackageOrderDTO.getMaincommoDity());
        parameterMap.put(Constants.PACKAGE_TYPE, gprsPackageOrderDTO.getPackageType());

        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, UrlConstants.ORDER_GPRS_PACKAGE);
        log.info("[{}] gprsPackageOrder request url is {}.", transId, methodUrl);

        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }

    /**
     * apn信息
     *
     * @param msisdn 物联卡号码
     * @param iccid 集成电路卡识别码
     * @param imsi 国际移动用户识别码
     * @param transId   流水号
     * @param accountId 账户ID
     * @return 返回 layui page info
     * @throws Exception
     * @author zhanlele
     * @date 20200313 17:09:18
     * @modify 20200313 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    public LayuiPageInfo singleCardApnInfo(String msisdn, String iccid, String imsi, String transId,
                                           String accountId) throws Exception {
        Map<String, String> paramMap = prepareRequestParam(msisdn, iccid, imsi, transId);
        // 单卡在线信息
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO cardOnlineResult = doRequestSingleCardOnlineInfo(true, accountId, paramMap);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!cardOnlineResult.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            //返回获取token的错误信息
            ErrorCode errorCode = ErrorCode.getByCode(cardOnlineResult.getCode());
            return LayuiPageFactory.cteateErrorMsg(errorCode);
        }
        // 获取token成功后解析api接口的响应结果
        String onlineResponseStr = cardOnlineResult.getMsg();
        String onlineCode = CommonUtil.getApiRspCode(onlineResponseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(onlineCode)) {
            log.warn("{} token [accountId:{}] is invalid and start to get a new token.", transId, accountId);
            cardOnlineResult = doRequestSingleCardOnlineInfo(false, accountId, paramMap);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!cardOnlineResult.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(cardOnlineResult.getCode());
                return LayuiPageFactory.cteateErrorMsg(errorCode);
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            onlineResponseStr = cardOnlineResult.getMsg();
        }
        log.info("[{}] query SingleCardOnlineInfo result string is {}.", transId, onlineResponseStr);
        // 单卡APN信息
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO apnInfoResult = doRequestSingleCardApnInfo(true, accountId, paramMap);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!apnInfoResult.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            //返回获取token的错误信息
            ErrorCode errorCode = ErrorCode.getByCode(apnInfoResult.getCode());
            return LayuiPageFactory.cteateErrorMsg(errorCode);
        }
        // 获取token成功后解析api接口的响应结果
        String apnResponseStr = apnInfoResult.getMsg();
        String apnCode = CommonUtil.getApiRspCode(apnResponseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(apnCode)) {
            log.warn("[{}] token [accountId:{}] is invalid and start to get a new token.", transId, accountId);
            apnInfoResult = doRequestSingleCardApnInfo(false, accountId, paramMap);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!apnInfoResult.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(apnInfoResult.getCode());
                return LayuiPageFactory.cteateErrorMsg(errorCode);
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            apnResponseStr = apnInfoResult.getMsg();
        }
        log.info("[{}] query SingleCardApnInfo result string is {}.", transId, apnResponseStr);
        //单卡在线信息，结果处理
        ResponseDto<OnlineInfoDTO> onlineResponse = JsonUtil.parseJson(onlineResponseStr,
                new TypeReference<ResponseDto<OnlineInfoDTO>>(){});
        onlineCode = onlineResponse.getStatus();
        //单卡APN信息，结果处理
        ResponseDto<ApnInfoDTO> apnResponse = JsonUtil.parseJson(apnResponseStr,
                new TypeReference<ResponseDto<ApnInfoDTO>>(){});
        apnCode = apnResponse.getStatus();

        List<Map<String, Object>> resultList = new ArrayList<>();
        if (ErrorCode.SUCCESS.getCode().equals(onlineCode) && ErrorCode.SUCCESS.getCode().equals(apnCode)) {
            //两个请求API都成功
            OnlineInfoDTO onlineInfo = onlineResponse.getResult().get(0);
            List<SimSessionDTO> simSessionList = onlineInfo.getSimSessionList();
            ApnInfoDTO apnInfo = apnResponse.getResult().get(0);
            List<ApnDTO> apnDTOList = apnInfo.getApnList();

            List<SimSessionDTO> removeSimSessionDTOList = new ArrayList<>();
            List<ApnDTO> removeApnDTOList = new ArrayList<>();
            for (SimSessionDTO simSessionDTO : simSessionList) {
                for (ApnDTO apnDTO : apnDTOList) {
                    if (apnDTO.getApnName().equalsIgnoreCase(simSessionDTO.getApnId())) {
                        Map<String, Object> map = new HashMap<>();
                        map.put(Constants.REQUEST_PARAM_APNNAME, apnDTO.getApnName());
                        map.put(Constants.SERVICE_STATUS, apnDTO.getStatus());
                        map.put(Constants.ONLINE_STATUS, simSessionDTO.getStatus());
                        map.put(Constants.IP_STR, simSessionDTO.getIp());
                        map.put(Constants.CREATE_DATE, simSessionDTO.getCreateDate());
                        map.put(Constants.RAT_TYPE, simSessionDTO.getRat());

                        resultList.add(map);
                        removeSimSessionDTOList.add(simSessionDTO);
                        removeApnDTOList.add(apnDTO);
                    }
                }
            }
            simSessionList.removeAll(removeSimSessionDTOList);
            apnDTOList.removeAll(removeApnDTOList);
            for (SimSessionDTO simSessionDTO : simSessionList) {
                Map<String, Object> map = new HashMap<>();
                map.put(Constants.REQUEST_PARAM_APNNAME, SEPARATE);
                map.put(Constants.SERVICE_STATUS, SEPARATE);
                map.put(Constants.ONLINE_STATUS, simSessionDTO.getStatus());
                map.put(Constants.IP_STR, simSessionDTO.getIp());
                map.put(Constants.CREATE_DATE, simSessionDTO.getCreateDate());
                map.put(Constants.RAT_TYPE, simSessionDTO.getRat());

                resultList.add(map);
            }
            for (ApnDTO apnDTO : apnDTOList) {
                Map<String, Object> map = new HashMap<>();
                map.put(Constants.REQUEST_PARAM_APNNAME, apnDTO.getApnName());
                map.put(Constants.SERVICE_STATUS, apnDTO.getStatus());
                map.put(Constants.ONLINE_STATUS, SEPARATE);
                map.put(Constants.IP_STR, SEPARATE);
                map.put(Constants.CREATE_DATE, SEPARATE);
                map.put(Constants.RAT_TYPE, SEPARATE);

                resultList.add(map);
            }
        } else if (!ErrorCode.SUCCESS.getCode().equals(onlineCode) && !ErrorCode.SUCCESS.getCode().equals(apnCode)) {
            //两个请求API都异常
            log.warn("[{}] query SingleCardOnlineInfo error message is {} ,and query SingleCardApnInfo " +
                    "error message is {}.", transId, onlineResponse.getMessage(), apnResponse.getMessage());
            Map<String, Object> map = new HashMap<>();
            map.put(Constants.REQUEST_PARAM_APNNAME, apnResponse.getMessage());
            map.put(Constants.SERVICE_STATUS, apnResponse.getMessage());
            map.put(Constants.ONLINE_STATUS, onlineResponse.getMessage());
            map.put(Constants.IP_STR, onlineResponse.getMessage());
            map.put(Constants.CREATE_DATE, onlineResponse.getMessage());
            map.put(Constants.RAT_TYPE, onlineResponse.getMessage());
            resultList.add(map);
        } else if (ErrorCode.SUCCESS.getCode().equals(onlineCode) && !ErrorCode.SUCCESS.getCode().equals(apnCode)) {
            //单卡在线查询成功，单卡APN查询异常
            log.warn("[{}] query SingleCardOnlineInfo success, but query SingleCardApnInfo error message is {}.",
                    transId, apnResponse.getMessage());
            OnlineInfoDTO onlineInfo = onlineResponse.getResult().get(0);
            List<SimSessionDTO> simSessionList = onlineInfo.getSimSessionList();
            for (SimSessionDTO simSessionDTO : simSessionList) {
                Map<String, Object> map = new HashMap<>();
                map.put(Constants.REQUEST_PARAM_APNNAME, apnResponse.getMessage());
                map.put(Constants.SERVICE_STATUS, apnResponse.getMessage());
                map.put(Constants.ONLINE_STATUS, simSessionDTO.getStatus());
                map.put(Constants.IP_STR, simSessionDTO.getIp());
                map.put(Constants.CREATE_DATE, simSessionDTO.getCreateDate());
                map.put(Constants.RAT_TYPE, simSessionDTO.getRat());
                resultList.add(map);
            }
        } else if (!ErrorCode.SUCCESS.getCode().equals(onlineCode) && ErrorCode.SUCCESS.getCode().equals(apnCode)) {
            //单卡在线查询异常，单卡APN查询成功
            log.warn("[{}] query SingleCardApnInfo success, but query SingleCardOnlineInfo error message is {}.",
                    transId, onlineResponse.getMessage());
            ApnInfoDTO apnInfo = apnResponse.getResult().get(0);
            List<ApnDTO> apnDTOList = apnInfo.getApnList();
            for (ApnDTO apnDTO : apnDTOList) {
                Map<String, Object> map = new HashMap<>();
                map.put(Constants.REQUEST_PARAM_APNNAME, apnDTO.getApnName());
                map.put(Constants.SERVICE_STATUS, apnDTO.getStatus());
                map.put(Constants.ONLINE_STATUS, onlineResponse.getMessage());
                map.put(Constants.IP_STR, onlineResponse.getMessage());
                map.put(Constants.CREATE_DATE, onlineResponse.getMessage());
                map.put(Constants.RAT_TYPE, onlineResponse.getMessage());
                resultList.add(map);
            }
        }

        Page<Map<String, Object>> page = LayuiPageFactory.defaultPage();
        page.setTotal(resultList.size());
        page.setRecords(resultList);

        page = new SimInfoForGprsWrapper(page).wrap();
        return LayuiPageFactory.createPageInfo(page);
    }

    /**
     * 封装请求参数
     *
     * @param msisdn 物联卡号码
     * @param iccid 集成电路卡识别码
     * @param imsi 国际移动用户识别码
     * @param transId
     * @return 返回 map
     * @author zhanlele
     * @date 20200313 17:16:58
     * @modify 20200313 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    private Map<String, String> prepareRequestParam(String msisdn, String iccid, String imsi, String transId) {
        Map<String, String> paramMap = new HashMap<>();
        if (StringUtils.isNotBlank(msisdn)) {
            paramMap.put(Constants.REQUEST_PARAM_MSISDN, msisdn);
        }
        if (StringUtils.isNotBlank(iccid)) {
            paramMap.put(Constants.REQUEST_PARAM_ICCID, iccid);
        }
        if (StringUtils.isNotBlank(imsi)) {
            paramMap.put(Constants.REQUEST_PARAM_IMSI, imsi);
        }
        paramMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        return paramMap;
    }

    /**
     * 调API，单卡在线信息
     *
     * @param tokenValid   token是否有效
     * @param accountId    账户ID
     * @param parameterMap
     * @return 返回 result dto
     * @throws Exception
     * @author zhanlele
     * @date 20200313 17:17:40
     * @modify 20200313 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    private ResultDTO doRequestSingleCardOnlineInfo(boolean tokenValid, String accountId,
                                                    Map<String, String> parameterMap) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, UrlConstants.QUERY_CARD_ONLINE_INFO);
        log.info("[{}] doRequestSingleCardOnlineInfo request url is {}.",
                parameterMap.get(Constants.REQUEST_PARAM_TRANSID), methodUrl);

        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }

    /**
     * 调API，单卡APN信息
     *
     * @param tokenValid   token是否有效
     * @param accountId    账户ID
     * @param parameterMap
     * @return 返回 result dto
     * @throws Exception
     * @author zhanlele
     * @date 20200313 17:18:30
     * @modify 20200313 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    private ResultDTO doRequestSingleCardApnInfo(boolean tokenValid, String accountId,
                                                 Map<String, String> parameterMap) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        parameterMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        String methodUrl = apiRequestUtil.buildRequestUrl(parameterMap, UrlConstants.QUERY_CARD_APN_INFO);
        log.info("[{}] doRequestSingleCardApnInfo request url is {}.",
                parameterMap.get(Constants.REQUEST_PARAM_TRANSID), methodUrl);

        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }

    /**
     * 套餐内用量
     *
     * @param accountId 账户ID
     * @param transId   流水号
     * @param msisdn 物联卡号码
     * @param iccid 集成电路卡识别码
     * @param imsi 国际移动用户识别码
     * @return 返回 layui page info
     * @throws Exception
     * @author zhanlele
     * @date 20200314 10:46:05
     * @modify 20200314 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    public LayuiPageInfo packageGprsUsed(String accountId, String transId, String msisdn,
                                         String iccid, String imsi) throws Exception {
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO resultDTO = doRequestPackageGprsUsed(true, accountId, transId, msisdn,
                iccid, imsi);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
            return LayuiPageFactory.cteateErrorMsg(errorCode);
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = resultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token [accountId:{}] is invalid and start to get a new token.", transId, accountId);
            resultDTO = doRequestPackageGprsUsed(false, accountId, transId, msisdn, iccid, imsi);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
                return LayuiPageFactory.cteateErrorMsg(errorCode);
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = resultDTO.getMsg();
        }
        log.info("[{}] query packageGprsUsed result string is {}.", transId, responseStr);
        ResponseDto<PackageGprsUsedDTO> responseDto = JsonUtil.parseJson(responseStr,
                new TypeReference<ResponseDto<PackageGprsUsedDTO>>(){});
        code = responseDto.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query packageGprsUsed error, error message is {}.", transId, responseDto.getMessage());
            return LayuiPageFactory.cteateErrorMsg(ErrorCode.getByCode(code));
        }

        List<PackageGprsUsedDTO> resultList = responseDto.getResult();
        PackageGprsUsedDTO packageGprsUsedDTO = resultList.get(0);
        List<AccmMarginDTO> accmMarginDTOList = packageGprsUsedDTO.getAccmMarginList();
        Page<AccmMarginDTO> page = LayuiPageFactory.defaultPage();
        page.setRecords(accmMarginDTOList);
        page.setTotal(accmMarginDTOList.size());
        return LayuiPageFactory.createPageInfo(page);
    }

    /**
     * 调API，套餐内用量
     *
     * @param tokenValid token是否有效
     * @param accountId  账户ID
     * @param transId    流水号
     * @param msisdn
     * @param iccid
     * @param imsi
     * @return 返回 result dto
     * @throws Exception
     * @author zhanlele
     * @date 20200313 17:41:15
     * @modify 20200313 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    private ResultDTO doRequestPackageGprsUsed(boolean tokenValid, String accountId, String transId,
                                               String msisdn, String iccid, String imsi) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        Map<String, String> paramMap = new HashMap<>();
        paramMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        paramMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        if (StringUtils.isNotBlank(msisdn)) {
            paramMap.put(Constants.REQUEST_PARAM_MSISDN, msisdn);
        }
        if (StringUtils.isNotBlank(iccid)) {
            paramMap.put(Constants.REQUEST_PARAM_ICCID, iccid);
        }
        if (StringUtils.isNotBlank(imsi)) {
            paramMap.put(Constants.REQUEST_PARAM_IMSI, imsi);
        }

        String methodUrl = apiRequestUtil.buildRequestUrl(paramMap, UrlConstants.QUERY_PACKAGE_GPRS_USED);
        log.info("[{}] packageGprsUsed request url is {}.", transId, methodUrl);

        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }

    /**
     * 流量池内用量
     *
     * @param accountId 账户ID
     * @param transId   流水号
     * @param msisdn 物联卡号码
     * @param iccid 集成电路卡识别码
     * @param imsi 国际移动用户识别码
     * @return 返回 layui page info
     * @throws Exception
     * @author zhanlele
     * @date 20200314 11:50:07
     * @modify 20200314 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    public LayuiPageInfo singleCardPoolUsed(String accountId, String transId, String msisdn,
                                            String iccid, String imsi) throws Exception {
        // 调用api接口：先获取token，然后带着token调用api接口
        ResultDTO resultDTO = doRequestSingleCardPoolUsed(true, accountId, transId, msisdn, iccid, imsi);
        // 如果此处响应失败即为获取token失败，返回失败原因
        if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
            return LayuiPageFactory.cteateErrorMsg(errorCode);
        }
        // 获取token成功后解析api接口的响应结果
        String responseStr = resultDTO.getMsg();
        String code = CommonUtil.getApiRspCode(responseStr);
        // 获取api接口的响应结果状态码，如果状态码为12021（token不存在或已过期），则重新获取token后再次调用api接口
        if (ErrorCode.ERR12021.getCode().equals(code)) {
            log.warn("[{}] token [accountId:{}] is invalid and start to get a new token.", transId, accountId);
            resultDTO = doRequestSingleCardPoolUsed(false, accountId, transId, msisdn, iccid, imsi);
            // 如果此处响应失败即为获取token失败，返回失败原因
            if (!resultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
                ErrorCode errorCode = ErrorCode.getByCode(resultDTO.getCode());
                return LayuiPageFactory.cteateErrorMsg(errorCode);
            }
            // 获取token成功后，重置responseStr（api接口的响应结果）
            responseStr = resultDTO.getMsg();
        }
        log.info("[{}] query singleCardPoolUsed result string is {}.", transId, responseStr);
        ResponseDto<SingleCardPoolUsedDTO> responseDto = JsonUtil.parseJson(responseStr,
                new TypeReference<ResponseDto<SingleCardPoolUsedDTO>>(){});
        code = responseDto.getStatus();
        if (!ErrorCode.SUCCESS.getCode().equals(code)) {
            // 如果api接口返回失败，则返回失败原因
            log.warn("[{}] query singleCardPoolUsed error, error message is {}.", transId, responseDto.getMessage());
            return LayuiPageFactory.cteateErrorMsg(ErrorCode.getByCode(code));
        }

        List<SingleCardPoolUsedDTO> resultList = responseDto.getResult();
        SingleCardPoolUsedDTO singleCardPoolUsedDTO = resultList.get(0);
        List<ApnUseDTO> apnList= singleCardPoolUsedDTO.getApnList();
        Page<ApnUseDTO> page = LayuiPageFactory.defaultPage();
        page.setTotal(apnList.size());
        page.setRecords(apnList);
        return LayuiPageFactory.createPageInfo(page);
    }

    /**
     * 调API，流量池内用量
     *
     * @param tokenValid token是否有效
     * @param accountId  账户ID
     * @param transId    流水号
     * @param msisdn 物联卡号码
     * @param iccid 集成电路卡识别码
     * @param imsi 国际移动用户识别码
     * @return 返回 result dto
     * @throws Exception
     * @author zhanlele
     * @date 20200314 11:04:21
     * @modify 20200314 zhanlele v1.1.2 创建
     * @since v1.1.2
     */
    private ResultDTO doRequestSingleCardPoolUsed(boolean tokenValid, String accountId, String transId,
                                                  String msisdn, String iccid, String imsi) throws Exception {
        ResultDTO tokenResultDTO = tokenService.getToken(tokenValid, accountId);
        if (!tokenResultDTO.getCode().equals(ErrorCode.SUCCESS.getCode())) {
            return tokenResultDTO;
        }

        Map<String, String> paramMap = new HashMap<>();
        paramMap.put(Constants.REQUEST_PARAM_TRANSID, transId);
        paramMap.put(Constants.REQUEST_PARAM_TOKEN, tokenResultDTO.getMsg());
        if (StringUtils.isNotBlank(msisdn)) {
            paramMap.put(Constants.REQUEST_PARAM_MSISDN, msisdn);
        }
        if (StringUtils.isNotBlank(iccid)) {
            paramMap.put(Constants.REQUEST_PARAM_ICCID, iccid);
        }
        if (StringUtils.isNotBlank(imsi)) {
            paramMap.put(Constants.REQUEST_PARAM_IMSI, imsi);
        }

        String methodUrl = apiRequestUtil.buildRequestUrl(paramMap, UrlConstants.QUERY_CARD_POOL_USED);
        log.info("[{}] singleCardPoolUsed request url is {}.", transId, methodUrl);

        tokenResultDTO.setMsg(apiRequestUtil.doGet(methodUrl));
        return tokenResultDTO;
    }
}
